﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using SockLib;
using System.Net;
using System.Data.SqlClient;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Threading;
using System.Diagnostics;
using System.IO;

namespace Socket服务器
{
    /// <summary>
    /// SocketManager.xaml 的交互逻辑
    /// </summary>
    public partial class SocketManager : Page,INotifyPropertyChanged 
    {
        public SocketManager(ServerConfig S)
        {
            InitializeComponent();
                  NewSC = S;
            serverinit(NewSC);
           DT = new DispatcherTimer();
            DT.Interval = new TimeSpan(0,3,0);
            DT.Tick += DT_Tick;
            W = new Writetxt(Write2Log);
            root.DataContext = this;
            loglist.ItemsSource = PLC;
        }



        DispatcherTimer DT;
        private void DT_Tick(object sender, EventArgs e)
        {
            IsPrint.IsChecked = false;
            IsAutoScroll.IsChecked = false;
            DT.Stop();
        }

        public    ServerConfig NewSC = new ServerConfig();
          SocketModelCollection SMC = new SocketModelCollection();  //datagrid数据源全部数据
        SocketModelCollection selectsmc = new SocketModelCollection(); //筛选的数据
        private object lockthis = new object();//锁对象
        #region 服务器属性设置
        private IPAddress _ServerIP;
          /// <summary>
          /// 服务器IP
          /// </summary>
          public IPAddress IP
          {
              set
              {
                  _ServerIP = value;
                  this.ServerIP.Text = _ServerIP.ToString();
                OnPropertyChanged("IP");
            }
              get
              { return _ServerIP; }
          }

          private   int _port;
          /// <summary>
          /// 服务器端口号
          /// </summary>
          public int Port
          {
              set
              {
                  _port = value;
                  ServerPort.Text = _port.ToString();
                OnPropertyChanged("Port");
            }
              get { return _port; }
          }


          private string _servername;
          /// <summary>
          /// 服务器名称
          /// </summary>
          public string SName
          {
              set
              {
                  _servername = value;
                  ServerName.Text = _servername;
                OnPropertyChanged("SName");
              }
              get
              {
                  return _servername;
              }
          }

          private bool _ISRun = false;
        /// <summary>
        /// 服务器是否运行
        /// </summary>
          public  bool ISRun
          {
              get { return _ISRun; }
              set
              {
                  _ISRun = value;
                if (ISRun == true)
                {
                    ServerStatue.Text = "启动";
                    Statue = ServerStatue.Text;
                }

                else
                {
                    ServerStatue.Text = "停止";
                    Statue = ServerStatue.Text;
                }
                OnPropertyChanged("ISRun");
            }
          }

        private  string _Statue;
        /// <summary>
        /// 服务器状态
        /// </summary>
        public string Statue
        {
             set
            {
                _Statue = value;
                OnPropertyChanged("Statue");
            }
            get
            {
                return _Statue;
            }
        }

        private DateTime _StartTime;
        /// <summary>
        /// 服务器启动时间
        /// </summary>
        public DateTime StartTime
        {
            set
            {
                _StartTime = value;
                OnPropertyChanged("StartTime");

            }
            get
            {
                return _StartTime;
            }
        }

        /// <summary>
        /// 在线的设备数量
        /// </summary>
        private string  _DCount;
        public string  DCount
        {
            set
            {
                _DCount = value + "/" + CapaCity;
                DeviceCount.Text = _DCount;
                OnPropertyChanged("DCount");
            }
            get
            {
                return _DCount;
            }
        }

        /// <summary>
        /// 服务器Button按钮文字
        /// </summary>
        private string _ServerContent;

        public string ServerContent
        {
            get { return _ServerContent; }
            set {
                _ServerContent = value;
                OnPropertyChanged("ServerContent");
            }
        }


        /// <summary>
        /// 服务器最大允许连入数量
        /// </summary>
        public int CapaCity { get; set; }

        #endregion


        /// <summary>
        /// 服务器初始化
        /// </summary>
        /// <param name="S"></param>
        void serverinit(ServerConfig S)
        {
            IP = S.ServerIP;
            SName = S.ServerName;
            Port = S.ServerPort;
            CapaCity = S.CapaCity;
            ISRun = false;
            ServerContent  = "启动服务";
            //DeviceMsg.ItemsSource = SMC;
            Logs.WriteLog LW = new Logs.WriteLog(Writelog);
            socketserver.PrintLog = LW;
        }

        #region 使用listbox写日志
        /// <summary>
        /// 要显示的日志集合
        /// </summary>
        PrintListColl PLC = new PrintListColl();
        /// <summary>
        /// 存储上次选中的日志，改变背景色
        /// </summary>
        PrintList SelectPL;

        private void loglist_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {         
            PrintList SPL = (PrintList)loglist.SelectedItem ;
            if (SPL != null)
            {
                SPL.BackColor = new SolidColorBrush(Color.FromArgb(80, 80, 80, 80));
                if (SelectPL != null)
                    SelectPL.BackColor = new SolidColorBrush(Colors.Transparent);
                SelectPL = SPL ;
                Clipboard.SetDataObject(SPL.WriteString );
            }
        }
        #endregion

        public SocketServer socketserver = new SocketServer();
        #region 写入日志

    
        /// <summary>
        /// 将数据写入日志
        /// </summary>
        /// <param name="ReceiveUid">收到的数据</param>
        /// <param name="TargetUid">目标ID</param>
        /// <param name="oper">操作类型
        /// <para >0：注册</para>
        /// <para>1:收到数据</para>
        /// <para>2:发送数据</para>
        /// <para>3：断开连接</para>
        /// <para>4:发送注册包,不显示</para>
        /// <para>5:心跳包,不显示</para>
        /// <para>10：服务器相关操作</para>
        /// </param>
        /// <param name="logstr">要显示的日志</param>
        void Write2Log(string ReceiveUid, string TargetUid, int oper, string logstr)
        {
            //记录写入操作日志sqlserver
            //LogData.WriteLogToSqlite(new object[] { Port, ReceiveUid, logstr });

            //记录写入操作日志sqlite
            //WriteDataLog2list(new object[] { Port, ReceiveUid, logstr });

            //记录写入操作日志日志文件
            //LogData.WriteLogToFile(logstr);
            try
            {
                if (DeviceGroup.SelectedIndex > 0 )
                {
                    if (ReceiveUid.Length > 5)
                    {
                        string group = ReceiveUid.Substring(1, 4); //获得组号,组号相同的才显示
                        if (group != DeviceGroup.SelectedItem.ToString())
                            return;
                    }
                    else
                        return;

                }
            }
            catch {; }

                if (IsPrint.IsChecked == true && oper != 4 && oper != 5)
                {
                    bool canprint = true;
                SolidColorBrush SCB = new SolidColorBrush();
                switch (oper)
                    {
                        case 0:
                            SCB = new SolidColorBrush(Color.FromRgb(255, 0, 0));
                            break;

                        case 1:
                            SCB = new SolidColorBrush(Color.FromRgb(0, 0, 255));
                            break;

                        case 2:
                            SCB = new SolidColorBrush(Color.FromRgb(128, 0, 0));
                            break;

                        case 3:
                            SCB = new SolidColorBrush(Color.FromRgb(255, 0, 0));
                            break;
                        case 4:
                            canprint = false;
                            break;
                        case 5:
                            canprint = false;
                            break;
                        case 6:
                            SCB = new SolidColorBrush(Color.FromRgb(158, 69, 85));
                            break;
                        case 10:
                            SCB = new SolidColorBrush(Color.FromRgb(0, 0, 0));
                            break;
                        default:
                            canprint = false;
                            break;
                    }

                if (canprint)
                {
                    PrintList PL = new PrintList() { WriteString = logstr, FontColor = SCB, BackColor = new SolidColorBrush(Colors.Transparent) };
                    PLC.Add(PL);
                    if (PLC.Count > 200)
                        PLC.RemoveAt(0);
                    if (IsAutoScroll.IsChecked ==true )
                        loglist.ScrollIntoView(loglist.Items[loglist.Items.Count - 1]);
                }




                //if (CanSql())
                //{
                //    string sqlstr = "insert into Logs values(@userid,@datetime,@TargetID,@SourceId,@OperType,@Logs,@Port)";
                //    SqlHelper.ExecuteNonQuery(sqlstr, System.Data.CommandType.Text,
                //        new SqlParameter("userid", 1),
                //        new SqlParameter("datetime", DateTime.Now),
                //        new SqlParameter("TargetID", TargetUid),
                //        new SqlParameter("SourceId", ReceiveUid),
                //        new SqlParameter("OperType", oper),
                //        new SqlParameter("Logs", logstr),
                //        new SqlParameter("Port", NewSC.ServerPort)
                //        );
                //}
            }
            
        }

        delegate void Writetxt(string ReceiveUid, string TargetUid, int oper, string txt);
        Writetxt W;

        void Writelog(string ReceiveUid, string TargetUid, int oper, string txt)
        {
           Dispatcher.Invoke(W, ReceiveUid, TargetUid, oper, txt);
            //Log.Dispatcher.Invoke(W, ReceiveUid, TargetUid, oper, txt);
        }

        #endregion
        void SourceChange(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            try
            {
                switch (e.Action)
                {

                    case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                        ADDItem((SocketModel)e.NewItems[0], e.NewStartingIndex);
                        break;

                    case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                        DELItem((SocketModel)e.OldItems[0], e.OldStartingIndex);
                        break;

                    case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                        break;

                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                LogException.WriteLogToFile(ex);
                Paragraph paragraph = new Paragraph();
                paragraph.LineHeight = 1;
                Run run = new Run() { Text = ex.ToString(), Foreground = new SolidColorBrush(Color.FromRgb(0, 0, 0)) };
                paragraph.Inlines.Add(run);
            }
             
        }
        struct itemsouce
        {
           public  SocketModel SM;
            public string Uid;
          public   int index;
        }

        void ADDGetGroup()
        {

            List<SocketModel> Group = SMC
              .GroupBy(p => new { p.DeviceGroup  })
              .Select(g => g.First())
              .ToList();  //获取不相同的group
            for (int i = 0; i <Group.Count; i++)
            {
                foreach (string txt in DeviceGroup.Items)
                {
                    if (txt == Group[i].DeviceGroup )
                        return;
                }
                DeviceGroup.Items.Add(Group[i].DeviceGroup);   //新来的加入
            }
        }


        #region 插入一条记录
        void ADDItem(SocketModel SM, int itemindex)
        {
            itemsouce Isource = new itemsouce();
            Isource.SM = SM;
            Isource.index = itemindex;
            Isource.Uid = SM.Uid;
            ADDSource(Isource);
        }

        void ADDSource(object ISource)
        {
            ADDIsource ADDIsources = new ADDIsource(ADDItems);
            DeviceGroup.Dispatcher.Invoke (ADDIsources, ISource);
        }
        delegate void ADDIsource(object ISource);
        void ADDItems(object ISource)
        {
            itemsouce Source = (itemsouce)ISource;
            SMC.Insert(Source.index, Source.SM);
            if (selectsmc.Count > 0 && Source.SM.DeviceGroup == selectsmc[0].DeviceGroup)  //如果组号一致也新增
                selectsmc.Add(Source.SM);
            DCount = SMC.Count.ToString();
            ADDGroup();
        }
        void ADDGroup()
        {

            List<SocketModel> Group = SMC
              .GroupBy(p => new { p.DeviceGroup })
              .Select(g => g.First())
              .ToList();  //获取不相同的group
            for (int i = 0; i < Group.Count; i++)
            {
                if (DeviceGroup.Items.Contains(Group[i].DeviceGroup))
                    continue ;
                DeviceGroup.Items.Add(Group[i].DeviceGroup);   //新来的加入
            }
        }
        #endregion

        #region 删除一条记录
        void DELItem(SocketModel SM, int itemindex)
        {
            itemsouce Isource = new itemsouce();
            Isource.SM = SM;
            Isource.index = itemindex;
            Isource.Uid = SM.Uid;
            DELSource(Isource);
        }

        void DELSource(object ISource)
        {
            DELIsource DELIsources = new DELIsource(DELItems);
            DeviceGroup.Dispatcher.Invoke (DELIsources, ISource);
        }
        delegate void DELIsource(object ISource);
        void DELItems(object ISource)
        {
            itemsouce Source = (itemsouce)ISource;
            SocketModel selectSM = new SocketModel();
            IEnumerable<SocketModel> query = from SocketModel sm in selectsmc   //如果查找的数据源中有，那么也需要删除
                        where sm.Uid == Source.SM.Uid
                        select sm;
            if (selectsmc.Count() == 1)   //查找到的数据只有1个，就改变数据源
            {
                if (DeviceGroup.Text == Source.SM.DeviceGroup)
                    DeviceGroup.SelectedIndex = 0;
            }
            else
            {
                foreach (SocketModel S in query)
                {
                    selectSM = S;
                }
                selectsmc.Remove(selectSM);
            }  
            SMC.Remove(Source.SM );
            DCount  = SMC.Count.ToString ();
            DELGroup();
        }



        void DELGroup()
        {

            List<SocketModel> Group = SMC
              .GroupBy(p => new { p.DeviceGroup })
              .Select(g => g.First())
              .ToList();  //获取不相同的group
            for (int j = DeviceGroup.Items.Count - 1; j > 0; j--)
            {
                bool candelete = true;
                for (int i = 0; i < Group.Count; i++)
                {
                    if (DeviceGroup.Items[j].ToString() == Group[i].DeviceGroup)  //找到要删除的项
                    {
                        candelete = false;
                        break;
                    }
                }
                if (candelete)
                {
                    DeviceGroup.Items.Remove(DeviceGroup.Items[j]);
                }

            }
        }
        #endregion

        /// <summary>
        /// 启动停止服务端口
        /// </summary>
        /// <param name="S"></param>
        /// <param name="IsTerminate"></param>
        /// <returns></returns>
        public string  ServerOper( ServerConfig   S )
        {
            if (ISRun == false)
            {
                string ip = "";
                DCount = "0";
                SocketEventPool.RegSocketModify RSM = new SocketEventPool.RegSocketModify(SourceChange);
                try
                {

                    if (socketserver.StartServer(S.ServerPort, S.CapaCity , S.ServerIP, out ip, RSM))
                    {
                        ISRun = true;
                        DeviceGroup.SelectedIndex = 0;
                        //ServerContorl.Content = "停止服务";
                        ServerContent = "停止服务";
                        string T = string.Format("{2} ,服务器启动：Ip={0},端口={1}", NewSC.ServerIP.ToString(), NewSC.ServerPort, DateTime.Now);
                        Write2Log("", "", 10, T);
                        StartTime = DateTime.Now;
                        return "停止服务";
                    }
                    else
                    {
                        string T = string.Format("服务器启动失败");
                        Write2Log("", "", 10, T);
                        return "启动服务";
                    }
                }
                catch (Exception ex)
                {
                    logexception.WriteLogToFile(ex);
                    string T = string.Format("服务器启动失败  "+ ex.Message );
                    Write2Log("", "", 10, T);
                    return "启动服务";
                }

            }
            else
            {
                if(MessageBox.Show("确认关闭该监听端口吗？","确认", MessageBoxButton.OKCancel )!= MessageBoxResult.OK  )
                    return "停止服务";
                socketserver.StopServer();
                ISRun = false;
                //ServerContorl.Content = "启动服务";
                ServerContent = "启动服务";
                SMC.Clear();
                selectsmc.Clear();
                string T = string.Format("{0} 服务器关闭",DateTime.Now );
                Write2Log("", "", 10, T);
                DCount = "0";
                return "启动服务";
            }

        }


        private void ServerContorl_Click(object sender, RoutedEventArgs e)
        {

            ServerOper(NewSC);

        }


        private void clearlog_Click(object sender, RoutedEventArgs e)
        {
            PLC.Clear();
        }

        private void DeviceGroup_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
           
            switch (DeviceGroup.SelectedIndex )
            {
                case 0:
                    DeviceMsg.ItemsSource = SMC;
                    selectsmc.Clear();
                    break;
                default:
                    selectsmc.Clear();
                    //lock (lockthis)
                    //{
                        IEnumerable<SocketModel> query = from SocketModel sm in SMC
                                    where sm.DeviceGroup == DeviceGroup.Items[DeviceGroup.SelectedIndex].ToString()
                                    select sm;
                        foreach (SocketModel S in query)
                        {
                            selectsmc.Add(S);
                        }
                    //}
                    DeviceMsg.ItemsSource = selectsmc;
                    break;

            }
        }

        public delegate bool Cansql();
        public Cansql CanSql;

       public  delegate void DeleteThis(SocketManager S);
        public DeleteThis DeleteServer;

     

        private void ShutDown_Click(object sender, RoutedEventArgs e)
        {
            if (ISRun == true)
                MessageBox.Show("必须先停止服务才能释放端口");
            else
            {
               if( MessageBox.Show("确定释放该端口吗？")== MessageBoxResult.OK)
                {
                    DeleteServer(this);
                   
                }
            }
           // FulshMemor();
            GC.Collect();
        }


        #region 释放内存
        [DllImport("kernel32.dll")]
        public static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max);

        public void FulshMemor()
        {
            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
        }

        #endregion

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyname)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
        }


        public void dispose()
        {
            GC.Collect();
        }

        private void IsPrint_Checked(object sender, RoutedEventArgs e)
        {
            DT.Start();
        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            DeviceGroup.SelectedIndex = 0;
        }

        private void ShowLog_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                string filename = Directory.GetCurrentDirectory() + "\\Log";
                Process.Start(filename);
            }
            catch (Exception)
            {
                MessageBox.Show("无日志文件查看");
            }
           
        }

        private void IsPrint_Unchecked(object sender, RoutedEventArgs e)
        {
            DT.Stop();
        }


    }
}
